home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 7
/
Aminet 7 - August 1995.iso
/
Aminet
/
comm
/
tcp
/
AmigaTCP.lha
/
AmigaTCP
/
src
/
amigadev.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-24
|
16KB
|
699 lines
/*
* Copyright (C) 1987
* Louis A. Mamakos WA3YMH
* All rights reserved.
*
* This code may not be redistributed, sold, included on any collection of
* software which is sold. Use of this software is restricted to inclusion
* in the KA9Q TCP/IP software package for use on a Commodore-Amiga system.
* Commercial use is prohibited. Only educational and Amateur Packet Radio
* use is allowed.
*/
#ifdef AMIGADEVDRV
/*
* This module is the meat of the Amiga 'internet.device' device driver. There
* are assembly language stubs in devstub.asm that call this module when user
* program access the device driver. Remember: the tasks running this code are
* not our own!
*/
#include <stdio.h>
/* Amiga system definitions */
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <exec/errors.h>
/* get definitions of KA9Q TCP/IP protocol stuff... */
#include "machdep.h"
#include "timer.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "icmp.h"
#include "ip.h"
#include "tcp.h"
#include "trace.h"
#include "session.h"
/* device driver specific definitions */
#define ListEmpty(x) (! ((x)->lh_Head->ln_Succ))
#include "inetdev.h"
#ifdef TRACE
#define tracedev(x) \
if (trace & TRACE_DEVICE) printf(x)
#define tracedev2(x,y) \
if (trace & TRACE_DEVICE) printf(x,y)
#define tracedev3(x,y,z) \
if (trace & TRACE_DEVICE) printf(x,y,z)
#define tracedev4(x,y,z,zz) \
if (trace & TRACE_DEVICE) printf(x,y,z,zz)
#endif
char *malloc();
extern void DSClose(), DSBeginIO(), DSAbortIO();
extern struct InternetBase *DSOpen();
extern long DSExpunge();
void indev_tcp_r_upcall(), indev_tcp_t_upcall(), indev_s_upcall();
struct SignalSemaphore INLock;
struct Library *MakeLibrary();
/* for open requests */
int nopens; /* from iface */
struct IOINETReq *iob = NULL;
int unit_spec;
struct InternetBase * dev;
int OpenIt = 0,
CN1 = 0,
IOpenedIt = 0;
extern int DeviceSignal;
extern struct Process *mytask;
printlist(l)
struct List *l;
{
printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail,
l->lh_TailPred);
}
/*
* Initialize and install the Amiga 'internet.device'.
*/
void
DriverInit()
{
char *foo[10];
int success;
static int WeWereHere;
int x;
tracedev("DriverInit");
x = WeWereHere;
WeWereHere = 1;
if (x)
{
printf("you tried to add the driver twice!!!\n");
return;
}
foo[0] = (char *) &DSOpen;
foo[1] = (char *) &DSClose;
foo[2] = (char *) &DSExpunge;
foo[3] = (char *) NULL;
foo[4] = (char *) &DSBeginIO;
foo[5] = (char *) &DSAbortIO;
/* add any other custom routines here */
foo[6] = (char *) -1;
InternetBase = (struct InternetBase *)
MakeLibrary(&foo[0], (char *) NULL, (char *) NULL,
(long) sizeof(struct InternetBase), (char *) NULL);
if (InternetBase == (struct InternetBase *) 0) {
/* display alert? */
return;
}
InitSemaphore(&(INLock));
ObtainSemaphore(&(INLock));
InitSemaphore(&(InternetBase->ib_lock));
InternetBase->ib_lock.ss_Link.ln_Pri = 0;
InternetBase->ib_lock.ss_Link.ln_Name = "internet.device lock";
NewList(&InternetBase->ib_Units);
InternetBase->ib_Units.lh_Type = NT_UNKNOWN;
InternetBase->lib.lib_Node.ln_Type = NT_DEVICE;
InternetBase->lib.lib_Node.ln_Pri = 0;
InternetBase->lib.lib_Node.ln_Name = "internet.device";
InternetBase->lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
InternetBase->lib.lib_Version = IN_VERSION;
InternetBase->lib.lib_Revision = IN_REVISION;
InternetBase->lib.lib_IdString =
(APTR) "internet.device 23 May 1987\r\n";
success = AddDevice(InternetBase);
Savea4();
OpenIt = 0;
IOpenedIt = 0;
nopens = 1;
CN1 = 5;
if (success != 0)
myoserr("driver open");
printf("driver added returned %d\n",success);
}
void
DriverShutdown()
{
long error;
extern long *RemoveDevice();
if (!InternetBase)
return;
if (error = RemDevice(InternetBase))
printf("Can't remove device: error %ld\n", error);
}
struct InternetBase *
NetDevOpen(mdev, munit_spec, miob, mflags)
struct InternetBase *mdev;
struct IOINETReq *miob;
ULONG munit_spec, mflags;
{
iob = miob;
dev = mdev;
unit_spec = munit_spec;
if (IOpenedIt == 1)
{
CN1++;
return NULL;
}
OpenIt = 1;
Permit();
while (IOpenedIt == 0);
Forbid();
IOpenedIt = 0;
return dev;
}
check_driver()
{
register struct INET_Unit *unit;
register struct tcb *tcb;
if (OpenIt != 0)
{
printf("open request!\n");
switch (unit_spec) {
case INET_UNIT_TCP:
case INET_UNIT_UDP:
break;
default:
iob->io_Error = IOERR_OPENFAIL;
iob->io_Device = NULL;
iob->io_Unit = NULL;
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
if ((unit = (struct INET_Unit *)
malloc(sizeof(struct INET_Unit))) == NULL) {
iob->io_Error = IOERR_OPENFAIL;
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
tracedev2("malloc ok %x\n", unit);
iob->io_Unit = unit;
iob->io_Device = (struct Device *)dev;
dev->lib.lib_OpenCnt++;
unit->iu_Unit.ln_Type = NT_UNKNOWN;
unit->iu_Unit.ln_Pri = 0;
NewList(&unit->iu_Input);
NewList(&unit->iu_Output);
printf("newlist ok\n");
unit->iu_Input.lh_Type = NT_UNKNOWN; /* gee, what do we really */
unit->iu_Output.lh_Type = NT_UNKNOWN; /* call these... */
unit->iu_user = iob->io_Offset; /* always returned in Offset */
unit->iu_Act_Input = NULL;
unit->iu_Act_Output = NULL;
iob->io_lsocket.address = ip_addr;
iob->io_lsocket.port = lport++;
AddTail(&InternetBase->ib_Units, &unit->iu_Unit);
/* perform protocol specific open functions */
printf("addtail\n");
switch (unit_spec) {
case INET_UNIT_TCP:
/* Forbid(); */
tcb = open_tcp(&(iob->io_lsocket), &(iob->io_fsocket),
(USHORT) iob->io_Offset, (USHORT) iob->io_TCP_Window,
indev_tcp_r_upcall, indev_tcp_t_upcall, indev_s_upcall,
iob->io_INET_TOS, (char *)unit);
/* Permit();*/
if (tcb == NULL)
goto fail;
unit->iu_Unit.ln_Name = "TCP Connection";
unit->iu_type = INET_UNIT_TCP;
unit->iu_ccb = tcb;
printf("cpopen is %d\n", tcb);
break;
default:
fail:
iob->io_Error = IOERR_OPENFAIL;
dev->lib.lib_OpenCnt--;
Remove(unit);
free(unit);
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
tracedev2("dev is %d\n", dev);
OpenIt = 0;
IOpenedIt = 1;
}
doneopen:
/* spin until that other guy is all done. We will not get through
* this spin until the other guy has done a Forbid() and
* then a Permit(), since the IopenedIt gets cleared
* AFTER the Forbid(). Sorry i do not use semaphores but
* i do not have 1.2 autodocs so am not totally up on their
* use.
*/
while (IOpenedIt);
}
CheckTcp()
{
struct Node *head = InternetBase->ib_Units.lh_Head;
struct INET_Unit *unit = (struct INET_Unit *) head;
struct tcb *tcb;
/* let the other guys in */
ReleaseSemaphore(&(INLock));
eihalt();
ObtainSemaphore(&(INLock));
tracedev("start checktcp\n");
tracedev4("heda %x Pred is %x Succ is %x\n", head,head->ln_Pred, head->ln_Succ);
for (;unit->iu_Unit.ln_Succ;unit = unit->iu_Unit.ln_Succ)
{
tracedev3("checktcp: %x Succ %d\n", unit, unit->iu_Unit.ln_Succ);
if (unit->iu_type != INET_UNIT_TCP)
{
tracedev("not a tcp\n");
continue;
}
tcb = (struct tcb *) unit->iu_ccb;
if (tcb == NULL)
{
tracedev("NULL tcb in unit\n");
continue;
}
if (tcb->state == ESTABLISHED)
{
tracedev("unit state is established!\n");
/* continue;*/
}
tracedev("do the upcall\n");
do_tupcall(tcb, 512); /* for now- it wil do the right thing */
if (tcb->rcvcnt > 0)
do_rupcall(tcb, tcb->rcvcnt);
}
tracedev("done checktcp\n");
/* ReleaseSemaphore(&(INLock));*/
}
void DevClose(dev, iob)
struct InternetBase *dev;
struct IOINETReq *iob;
{
register struct INET_Unit *unit;
struct tcb *tcb;
unit = iob->io_Unit;
tcb = unit->iu_ccb;
del_tcp(tcb);
Remove(unit);
free(unit);
iob->io_Unit = NULL;
iob->io_Device = (struct Device *)dev;
dev->lib.lib_OpenCnt--;
/* remove iu_Unit from ib_Units list */
/* decrement library use count */
/* free unit structure */
/* delete TCP/UDP connection del_tcp()/del_udp() */
}
long DevExpunge(dev)
struct InternetBase *dev;
{
register char *m;
register long len;
if (InternetBase->lib.lib_OpenCnt) {
InternetBase->lib.lib_Flags |= LIBF_DELEXP;
return 0;
}
Remove(InternetBase); /* remove from library list */
len = InternetBase->lib.lib_NegSize + InternetBase->lib.lib_PosSize;
m = (char *) ((ULONG)InternetBase - InternetBase->lib.lib_NegSize);
FreeMem(m, len);
return 0;
}
#define C_IMMED (1<<0)
#define C_READ (1<<1)
#define C_WRITE (1<<2)
void cmd_Invalid(), cmd_Reset(), cmd_Read(), cmd_Write(), cmd_Update(),
cmd_Clear(), cmd_Stop(), cmd_Start(), cmd_Flush(), PerformIO();
struct Commands {
void (*cmd_func)();
int cmd_flags;
} commands [] = {
{ cmd_Invalid, C_IMMED }, /* invalid */
{ cmd_Reset, C_IMMED }, /* CMD_RESET */
{ cmd_Read, C_READ }, /* CMD_READ */
{ cmd_Write, C_WRITE }, /* CMD_WRITE */
{ cmd_Update, C_WRITE }, /* CMD_UPDATE */
{ cmd_Clear, C_IMMED }, /* CMD_CLEAR */
{ cmd_Stop, C_IMMED }, /* CMD_STOP */
{ cmd_Start, C_IMMED }, /* CMD_START */
{ cmd_Flush, C_IMMED }, /* CMD_FLUSH */
};
/* define last valid command */
#define MAX_IO_COMMAND CMD_FLUSH
/* BeginIO is called to begin processing of the I/O request */
void DevBeginIO(iob, dev)
struct IOINETReq *iob;
struct InternetBase *dev;
{
register struct Commands *cmd;
register struct INET_Unit *unit = iob->io_Unit;
ObtainSemaphore(&(INLock));
if (iob->io_Command > MAX_IO_COMMAND) {
cmd_Invalid(iob, iob->io_Unit);
goto done;
}
tracedev("io. ObtainSme\n");
tracedev("got it\n");
cmd = &commands[iob->io_Command];
tracedev2("cmd is %d\n",iob->io_Command);
tracedev2("flags %d\n", iob->io_Flags);
if ((cmd->cmd_flags & C_IMMED) == 0) {
/*
* Code for commands which can queue
*/
if ((cmd->cmd_flags & C_READ)/* && (unit->iu_Act_Input)*/) {
AddTail(&unit->iu_Input, iob);
iob->io_Flags &= ~IOF_QUICK;
iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
tracedev3("added %d to read queue of unit %d\n", iob, unit);
goto done;
}
if ((cmd->cmd_flags & C_WRITE)/* && (unit->iu_Act_Output)*/) {
AddTail(&unit->iu_Output, iob);
iob->io_Flags &= ~IOF_QUICK;
iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
tracedev3("added %d to write queue of unit %d\n", iob, unit);
goto done;
}
}
PerformIO(iob, unit);
done: tracedev4("flags QUI %x ~QUI %x %d\n", IOF_QUICK, ~IOF_QUICK,
iob->io_Flags);
Signal(mytask, DeviceSignal);
ReleaseSemaphore(&(INLock));
}
void DevAbortIO(iob, dev)
struct IOINETReq *iob;
struct InternetBase *dev;
{
printf("DevAbortIo\n");
}
void
PerformIO(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = 0;
iob->io_Actual = 0;
(*commands[iob->io_Command].cmd_func)(iob, unit);
}
void
TermIO(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
struct tcb *tcb;
tcb = (struct tcb *) unit->iu_ccb;
iob->io_OldState = iob->io_State;
iob->io_State = tcb->state;
if ((iob->io_Flags & IOF_QUICK) == 0)
/* not quick I/O */
ReplyMsg(&iob->io_Message);
}
void
cmd_Invalid(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Reset(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Read(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Write(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Update(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Clear(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Stop(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Start(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Flush(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
/* TCP receiver upcall routine. Called with TCB pointer and number of bytes
available */
do_rupcall(tcb, cnt)
struct tcb *tcb;
int16 cnt;
{
struct mbuf *bp;
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
int amount, recamount;
struct IOINETReq *iob;
/* ObtainSemaphore(&(INLock));*/
if (ListEmpty(&(unit->iu_Input)))
goto done;
iob = unit->iu_Act_Input = unit->iu_Input.lh_Head;
tracedev4("dev rupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
if (iob != NULL)
{
Remove(iob);
amount = min(cnt, iob->io_Length);
tracedev3("call recv_tcp %d bytes avail %d\n", amount, cnt);
recamount = recv_tcp(tcb, &bp, amount);
iob->io_Actual = dqdata(bp, iob->io_Data, recamount);
tracedev2("recv_tcp after got %d bytes\n", iob->io_Actual);
TermIO(iob, unit);
/* ReplyMsg(&(iob->io_Message));*/
}
done:
/* ReleaseSemaphore(&(INLock)); */
}
/* TCP receiver upcall routine. Called with TCB pointer and number of bytes
available */
void
indev_tcp_r_upcall(tcb, cnt)
struct tcb *tcb;
int16 cnt;
{
/* ObtainSemaphore(&(INLock));*/
do_rupcall(tcb, 512);
/* ReleaseSemaphore(&(INLock)); */
}
/* TCP transmitter upcall routine. Called with TCB pointer and number of bytes
free in send window */
do_tupcall(tcb, avail)
struct tcb *tcb;
int16 avail;
{
struct mbuf *bp, *qdata();
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
int amount;
struct IOINETReq *iob;
if (ListEmpty(&(unit->iu_Output)))
goto done;
tracedev("non-empty Output\n");
iob = unit->iu_Act_Output = unit->iu_Output.lh_Head;
tracedev4("dev tupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
if (iob != NULL)
{
Remove(iob);
amount = min(avail, iob->io_Length);
tracedev3("t_upcall- send_tcp for addr %x %d bytes\n",iob->io_Data,
amount);
bp = qdata(iob->io_Data, amount);
iob->io_Actual = send_tcp(tcb, bp);
tracedev2("send_tcp after got %d bytes\n", iob->io_Actual);
TermIO(iob, unit);
/* ReplyMsg(&(iob->io_Message));*/
unit->iu_Act_Output = NULL;
}
done:
}
void
indev_tcp_t_upcall(tcb, avail)
struct tcb *tcb;
int16 avail;
{
/* ObtainSemaphore(&(INLock));*/
do_tupcall(tcb, avail);
/* ReleaseSemaphore(&(INLock)); */
}
void
indev_s_upcall(tcb, old, new)
struct tcb *tcb;
char old, new;
{
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
char notify = 0;
extern char *tcpstates[];
extern char *reasons[];
extern char *unreach[];
extern char *exceed[];
/* Can't add a check for unknown connection here, it would loop
* on a close upcall! We're just careful later on.
*/
if(unit != NULL)
notify = 1;
switch(new){
case CLOSE_WAIT:
if(notify)
printf("%s\r\n",tcpstates[new]);
close_tcp(tcb);
break;
case CLOSED: /* court adjourned */
if(notify){
printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
if(tcb->reason == NETWORK){
switch(tcb->type){
case DEST_UNREACH:
printf(": %s unreachable",unreach[tcb->code]);
break;
case TIME_EXCEED:
printf(": %s time exceeded",exceed[tcb->code]);
break;
}
}
printf(")\r\n");
}
del_tcp(tcb);
break;
default:
if(notify)
printf("%s\r\n",tcpstates[new]);
break;
}
fflush(stdout);
}
#endif